#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <linux/types.h> /* for videodev2.h */
#include <sys/mman.h>
#include <linux/input.h>

#if 0
type，指事件类型，常见的事件类型有：
EV_KEY，按键事件，键盘的按键，鼠标的左键右键等；
EV_REL，相对坐标，主要用于鼠标的移动事件；
EV_ABS，绝对坐标，主要用于触摸屏的移动事件。

code 事件代码，当事件类型为EV_KEY时，该代码为设备键盘代码，
在input.h文件中以KEY_开头定义；
value 事件的值，当事件类型代码是EV_KEY时，按键操作值为1，释放操作值为0，
事件类型代码为EV_REL是，value为正数值和负数值分别代表连个不同方向的值。
#endif

#define GPIO_KEYS_EVETN "/dev/input/event0"
int main(int argc, char const *argv[])
{
    int fd = 0;
    struct epoll_event ev, events[10];
    int nfds = 0, epollfd = 0, n = 0;
    int ret = 0;
    struct input_event evt;

    fd = open(GPIO_KEYS_EVETN, O_RDWR);
    if (fd < 0) {
        perror("open failed\n");
    }

    epollfd = epoll_create1(0);
    if (epollfd == -1)
    {
        perror("epoll_create1");
        return -1;
    }

    ev.events = EPOLLIN;
    ev.data.fd = fd;
    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1)
    {
        perror("epoll_ctl: listen_sock");
        return -1;
    }

    while (1)
    {
        nfds = epoll_wait(epollfd, events, 10, -1); // 500ms, -1表示阻塞
        if (nfds == -1)
        {
            /* 小于0时,可以获取 */
            perror("epoll_wait");
            return -1;
        }
        else if (nfds == 0)
        {
            /* 驱动中返回0 */
            printf("timeout\n");
        }
        else
        {
            for (n = 0; n < nfds; ++n)
            {
                if (events[n].data.fd == fd)
                {
                    if (events[n].events & EPOLLIN)
                    {
                        memset(&evt, 0, sizeof(evt));
                        ret = read(fd, &evt, sizeof(evt));
                        if (ret < 0) {
                            perror("read failed\n");
                            close(events[n].data.fd);
                            epoll_ctl(epollfd, EPOLL_CTL_DEL, events[n].data.fd, &ev);
                            return -1;
                        }
                        
                        if (evt.type == EV_KEY) {
                            // event.value ? "Pressed" : "Released"
                            if (evt.code == KEY_UP && evt.value == 1) {
                                printf("UP\n");
                            } else if (evt.code == KEY_DOWN && evt.value == 1) {
                                printf("DOWN\n");
                            } else if (!(evt.code == KEY_UP || evt.code == KEY_DOWN)) {
                                printf("Unknow code\n");
                            }
                        }
                    }
                }
            }
        }
    }

    close(fd);

    return 0;
}
